<?php
import('ORG.Util.String');

// 消息处理类
class MaterialKeywordAction extends Action {
    
    /* 添加关键字和素材对应关系
	 * mid：						对应的素材名称
	 * keys:					关键字列表
	 * matchs:					匹配类别列表，必须与keys的数量匹配
	 * http://localhost/MaterialKeyword/add.json/mids/4,6/keys/key1,key2/matchs/1,0/rname/name
	*/
	public function add($mids,$keys,$matchs,$rname='',$deleted=0){
		$retVal = Session::init();
 		if (!$retVal) {
			Output::instance()->resultCode(code_access_denied);
			return;
		}
		
		$keywordExist = $this->isKeywordExist($keys);
		if ($keywordExist) {
			Output::instance()->resultCode(code_keyword_repeat, $keywordExist. " 关键字重复");
			return;
		}
		
		$id = $this->addData($mids, $keys, $matchs, $rname, $deleted);
		
		$result = new stdClass();
		$result->code = 0;
		$result->id = $id;
		$result->ruleName = $rname;
		$result->updateTime = $time;
		Output::instance()->object($result);
		
    }

    /**
     * 添加关键字与素材的关联
     *
     * @param        $mids      素材id
     * @param        $keys      关键字, 使用 "," 分割
     * @param        $matchs    匹配优先级
     * @param string $rname
     * @param int    $deleted
     * @return string
     */
    public function addData($mids,$keys,$matchs,$rname='',$deleted=0) {
    	// 初始化模型
    	$MaterialKeyword = D("MaterialKeyword");
    	
    	// 先分割mids
    	$midarr = explode(',',$mids);
    	// 先用,分割keys
    	$keyarr = explode(',',$keys);
    	$matchs = explode(',', $matchs);

    	$id = Encryption::uuid();
    	$time = date('Y-m-d H:i:s');
    	
    	// 添加多个关键字对应的多个素材(依次返回)
    	for ($i=0; $i<count($midarr); $i++) {
    		for ($j=0; $j<count($keyarr); $j++) {
    			$existCondition['keyword'] = array('eq',$keyarr[$j]);
    			$existCondition['deleted'] = 0;
    			$existKeyword = $MaterialKeyword->where($existCondition)->find();
    			if($existKeyword){
    				Output::instance()->resultCode(code_keyword_repeat,$keyarr[$j]. " 关键字重复");
    				return;
    			}
    			// 插入到keyword表中
    			$MaterialKeyword->create();
    			$MaterialKeyword->id = $id;
    			$MaterialKeyword->ruleName = $rname;
    			$MaterialKeyword->materialId = $midarr[$i];
    			$MaterialKeyword->keyword = $keyarr[$j];
    			if(count($matchs) == 1){
    				$MaterialKeyword->exactMatch = $matchs[0];
    			}else{
    				$MaterialKeyword->exactMatch = $matchs[$j];
    			}
    			$MaterialKeyword->updateTime = $time;
    			$MaterialKeyword->deleted = $deleted;
    			$MaterialKeyword->add();
    			// 				Log::write('update add materialkeyword sql :'.$MaterialKeyword->getLastSql());
    		}
    	}
    	
    	R('Log/add', array(module_handle_keyword, $id, op_add, $keys));
    	
    	return $id;
    }
    
    /* 获取关键字列表
     * showSystemKeyword: 是否显示默认和被关注回复
     * start:
	 * limit:
	 * kw:用来匹配对应的素材
     */
    public function index($kw='',$showSystemKeyword = true, $module='', $deleted = null, $order="updateTime", $orderBy="desc", $start=0, $limit=25){
    	$retVal = Session::init();
 		if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}
    	$MaterialKeyword = D("MaterialKeyword");
    	
    	$cid = 	Session::$user['customerId'];
    	if ($cid == 0) {
    		$prefix = C('ORIGINAL_DB_PREFIX');
    	} else {
    		$prefix = C('ORIGINAL_DB_PREFIX').$cid.'_';
    	}
    	
    	if (!$showSystemKeyword) {
    		$map['keyword'] = array(array('neq', keyword_default_reply), array('neq', keyword_system_subscribe), 'and') ; 
    	}
    	if ($module != '') {
    		$moduleArray = explode(",", $module);
    		$mapArr = array();
    		foreach ($moduleArray as $m) {
    			array_push($mapArr, array('eq', $m));
    		}
    		array_push($mapArr, "or");
    		$map[$prefix . "material.module"] = $mapArr;
    	}
    	if (isset($deleted)) {
    		$map["keyword.deleted"] = $deleted;
    	}
    	if(!empty($kw)){
    		$map["keyword.keyword"] = array("like",'%'.trim($kw).'%');
    	}
    	 
    	$sql = $MaterialKeyword->alias('keyword')->distinct(true)->field('keyword.id')->join($prefix .'material ON keyword.materialId = ' . $prefix .'material.id')->
    		field("keyword.id")->where($map)->order("keyword.$order $orderBy")->limit("$start,$limit")->select(false);
    	
    	$count = count($MaterialKeyword->alias('keyword')->distinct(true)->field('keyword.id')->join($prefix .'material ON keyword.materialId = ' . $prefix .'material.id')->
    			field("keyword.id")->where($map)->select());
    	
    	$sqlKw = $MaterialKeyword->field("id")->table($sql)->alias("t")->select(false);
    	$where['_string'] = "id IN ( $sqlKw )";
    	$arr = $MaterialKeyword->where($where)->order("$order $orderBy")->select();
//     	echo $MaterialKeyword->getLastSql();

    	$Material = D("Material");
    	$sqlMater = $MaterialKeyword->field("materialId")->table($sqlMater)->alias("t")->select(false);
    	$condition['_string'] = "material.id IN ( $sqlMater )";
    	$arrMaterial = $Material->alias('material')->where($condition)->order("$order $orderBy")->join('wx_module_group ON material.module = wx_module_group.group')->
				field('material.*, wx_module_group.iconurl')->select();
//     	echo $Material->getLastSql();
    	$result = array();
    	foreach ($arr as $keyword) {
    		if (strcmp($keyword['id'], $current->id) != 0) {
    			$current = new stdClass();
    			$current->id = $keyword['id'];
    			$current->ruleName = $keyword['ruleName'];
    			$current->updateTime = $keyword['updateTime'];
    			$current->keywords = array();
    			array_push($current->keywords, (object)array(
    					'keyword'=> $keyword['keyword'], 
    					'exactMatch'=> $keyword['exactMatch']));
    			$current->material = new stdClass();
    			foreach ($arrMaterial as $mater) {
    				if ($mater['id'] == $keyword['materialId']) {
    					// replace html
    					if ($mater['xml'] != '') {
    						$mater['xml'] = nl2br($mater['xml']);
    					}
    					$current->material = $mater;
    					break;
    				}
    			}
    			array_push($result, $current);
    		} else {
    			array_push($current->keywords, (object)array(
    					'keyword'=> $keyword['keyword'],
    					'exactMatch'=> $keyword['exactMatch']));
    		}
    	}
    	Output::instance()->objArray($result, $count);
    }
    
    /* 删除指定ID的关键字
     * gid: 组名称
     */
    public function delete($id){
    	$retVal = Session::init();
 		if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}
    	
    	// 初始化模型
    	$MaterialKeyword = D("MaterialKeyword");
    	// 删除该组所有的关键字
    	$condition['id'] = array('eq',$id);
    	$kw = $MaterialKeyword->where($condition)->find();
//     	Log::write('delete materialKeyword sql is:'.$MaterialKeyword->getLastSql());
    	//$MaterialKeyword->find($id);
    	$MaterialKeyword->deleted = 1;
    	$result = $MaterialKeyword->save();
    	
		Output::instance()->resultCode(code_success, 'OK');
		
		R('Log/add', array(module_handle_keyword, $id, op_delete, $kw["keyword"]));
    }
    
    /* 修改指定ID的关键字
     * gname: 组名称
     * mids: 返回的一组素材
     * keys: 一组关键字
     * matchs: 一组关键字对应的一组匹配规则
    */
    public function update($id, $mids,$keys,$matchs, $rname='',$deleted=0){
    	$retVal = Session::init();
    	if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}
    	
    	// 初始化模型
		$MaterialKeyword = D("MaterialKeyword");	
		

		$map['id'] = array('in',$id);
		
		// 删除该组所有的关键字
		$MaterialKeyword->where($map)->delete();
// 		$MaterialKeyword->where("id='$id'")->delete();
		
// 		Log::write('update delete materialkeyword sql :'.$MaterialKeyword->getLastSql());
		// 再重新插入所有的关键字,add方法输出output了
		$this->add($mids,$keys,$matchs,$rname,$deleted);	
		R('Log/add', array(module_handle_keyword, $id, op_update, $keys));
    } 
    
    /*
     * 获取系统关键字对应的素材
     * keyword: 关键字，多个用逗号分隔
     */
    public function getSystemKeywordMaterial($keyword, $deleted = null) {
    	$retVal = Session::init();
    	if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}
    	
    	$map["keyword"] = $keyword;
    	if (isset($deleted)) {
    		$map["deleted"] = $deleted;
    	}
    	
    	$MaterialKeyword = D("MaterialKeyword");
    	$kw = $MaterialKeyword->where($map)->find();
    	if (!$kw) {
    		Output::instance()->resultCode(code_success, '没有找到关键字');
    		return;
    	}
//     	echo $MaterialKeyword->getLastSql(); 
    	 
    	$Material = D("Material");
    	$mid = $MaterialKeyword->field("materialId")->where($map)->find();
    	if (!$mid) {
    		Output::instance()->resultCode(code_success, '没有找到对应素材');
    		return;
    	}
		$mid = $mid["materialId"];
    	$condition['_string'] = "material.id IN ( $mid )";
    	$mater = $Material->alias('material')->where($condition)->join('wx_module_group ON material.module = wx_module_group.group')->
    		field('material.*, wx_module_group.iconurl')->find();
//        	echo $Material->getLastSql();
    	
    	$result = new stdClass();
   		$result->id = $kw['id'];
 		$result->ruleName = $kw['ruleName'];
 		$result->updateTime = $kw['updateTime'];
 		$result->material = new stdClass();
    	// replace html
		if ($mater['xml'] != '') {
 			$mater['xml'] = nl2br($mater['xml']);
   		}
    	$result->material = $mater;
    	 
    	Output::instance()->object($result);
    }

    /**
     * 添加消息互动
     *
     * *param        $id            素材关键字表的id
     * *param        mids           素材在咱们平台数据库的id
     * @param        $name          素材名称
     * @param        $module        text-文字/news-图文
     * @param        $xml           内容
     * @param        $keys          system_subscribe/default_reply/关键字
     * @param        $matchs        1 -> 是否完全匹配 1-是/0-非
     * @param string $tags
     * @param int    $deleted
     * @param null   $accessTag     访问标签, 以 "," 分割
     */
    public function addMaterialAndKeyWord($name, $module, $xml, $keys, $matchs, $tags='', $deleted=0, $accessTag=NULL) {
    	$retVal = Session::init();
    	if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}

    	// TODO: 这里考虑一个整体的重复
        // 1. 通过$keys去查找包含这个key的整个分组
        // 2. 如果这些key刚好包含在一个分组里
    	if(!empty($keys)) {
	    	$keywordExist = $this->isKeywordExist($keys);
	    	if ($keywordExist) {
	    		Output::instance()->resultCode(code_keyword_repeat, $keywordExist. " 关键字重复");
	    		return;
	    	}
    	}

    	// TODO: 这里应该不用修改参数使用一次性存储
        // 1. 使用单个存储, 存进去之后
        // 2. 再次增加这个keys整体对应的素材id
    	$mid = R('Material/addData', array($name,$module,$xml,$public='',$type='',$groupId='',$tags,$deleted,NULL,$accessTag));
    	if (!$mid) {
    		return;
    	}

    	// TODO: 可能是修改
    	if(!empty($keys)) {
    		$id = $this->addData($mid, $keys, $matchs, '', $deleted);
    	}
    	
    	Output::instance()->resultCode();
    }
    /*
     * id：关键词id如果没有关键字则传空只更新素材
     */
    public function updateMaterialAndKeyWord($name, $module, $xml, $keys, $matchs, $mids,$keys,$matchs,$tags='', 
    		$id= '', $rname='',$deleted=0,$accessTag=NULL){
    	$retVal = Session::init();
    	if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}
    	
    	$keywordExist = $this->isKeywordExist($keys, $id);
    	if ($keywordExist) {
    		Output::instance()->resultCode(code_keyword_repeat, $keywordExist. " 关键字重复");
    		return;
    	}
    	$result = R('Material/updateData', array($mids, '',$module,$xml,$tags,$deleted,$accessTag));
    	if (!$result) {
    		return;
    	}
    	if (!empty($id)) {
	    	// 初始化模型
	    	$MaterialKeyword = D("MaterialKeyword");
	    
	    	$map['id'] = array('in',$id);
	    
	    	// 删除该组所有的关键字
	    	$MaterialKeyword->where($map)->delete();
	    	// 		$MaterialKeyword->where("id='$id'")->delete();
	    	// 		Log::write('update delete materialkeyword sql :'.$MaterialKeyword->getLastSql());
	    	// 再重新插入所有的关键字,add方法输出output了
	    	$this->add($mids,$keys,$matchs,$rname,$deleted);
    	} else if (!empty($keys)) {
    		$this->addData($mids, $keys, $matchs, $rname,$deleted);
    	} else {
    		Output::instance()->resultCode();
    	}
    }
    
    private function isKeywordExist($keys, $id = '') {
    	// 初始化模型
    	$MaterialKeyword = D("MaterialKeyword");
    	
    	// 先用,分割keys
    	$keyarr = explode(',',$keys);
    	for ($j = 0; $j < count($keyarr); $j++) {
    		if (!empty($id)) {
    			$existCondition['id'] = array('neq', $id);
    		}
    		$existCondition['keyword'] = array('eq',$keyarr[$j]);
    		$existCondition['deleted'] = 0;
    		$existKeyword = $MaterialKeyword->where($existCondition)->find();
    		if($existKeyword){
    			return $keyarr[$j];
    		}
    	}
    	
    	return null;
    }
    
    /**
     * 删除指定素材对应的关键字
     * @param unknown_type $mid
     */
    public function deleteByMaterialId($mid){
    	$retVal = Session::init();
    	if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}
    	// update MaterialKeyword set deleted = 1 where materialId = mid;
    	//DELETE FROM MaterialKeyword WHERE materialId  = mid;
    	// 初始化模型
    	//     	$MaterialKeyword = D("MaterialKeyword");
    	//     	// 删除该组所有的关键字
    	//     	$condition['materialId'] = array('eq',$mid);
    	//     	$MaterialKeyword->where($condition)->select();
    	//     	//$MaterialKeyword->find($id);
    	//     	$MaterialKeyword->deleted = 1;
    	//     	$result = $MaterialKeyword->save();
    	 
    	$cid = Session::$user["customerId"];
    	 
    	if($cid == 0){
    		$prefix = C('ORIGINAL_DB_PREFIX');
    	}else{
    		$prefix = C('ORIGINAL_DB_PREFIX').$cid.'_';
    	}
    	$MaterialKeyword = new Model();
    	 
    	$sql = ' update '.$prefix.'material_keyword set deleted = 1 where materialId =  "'.$mid.'"';
    	$MaterialKeyword->query($sql);
//     	Log::write('update  materialKeyword  by materialID sql is:'.$MaterialKeyword->getLastSql());
    	Output::instance()->resultCode(code_success);
    }
    
    public function updateByMaterialId($mid,$keys,$matchs, $rname='',$deleted=0){

    	$retVal = Session::init();
    	if (!$retVal) {
    		Output::instance()->resultCode(code_access_denied);
    		return;
    	}
    	 
    	// 初始化模型
    	$MaterialKeyword = D("MaterialKeyword");
    	// 删除该组所有的关键字
    	$MaterialKeyword->where("materialId='$mid'")->delete();
//     	Log::write('update materialkeyword by materialId sql :'.$MaterialKeyword->getLastSql());
    	// 再重新插入所有的关键字,add方法输出output了
    	$this->add($mid,$keys,$matchs,$rname,$deleted);
    	
    }

    /**
     * ********************************************************************************************************
     */

    /**
     * 设置关键字
     *
     * @param null   $id            关键字id
     * @param        $mediaId       自媒体id
     * @param        $keys          关键字长串, 多个关键字使用 "," 分割
     * @param int    $exactMatch
     * @param string $ruleName
     */
    public function setKeys($id = NULL, $mediaId, $keys, $exactMatch = 1, $ruleName = '', $needReturn = false)
    {
        /**
         * 1. 这里先单独添加关键字
         *      如果带了关键字id, 则这里是修改, 对keys进行差集修改
         *      如果没带关键字id, 则是新增, 走新增逻辑即可
         * 2. 然后添加素材后, 关联素材和关键字
         *
         * 修改:
         *      1. 关键字允许重复, 不允许关键字整体重复
         *      2. 素材首次未添加时默认是空的
         */

        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$needReturn && !$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $MaterialKeyword_Model  = M('material_keyword');

        /** 注意: 这里新增包含一个内部新建 - 被添加自动回复 & 消息默认回复 */
        if (!isset($id)) {  /** 如果没有设置keys的id, 则这里是新增 */

            /** 3. key关键字重复判断 */
            if(!$needReturn && !empty($keys)) {
                $keywordExist = $this->isKeywordExist($keys);
                if ($keywordExist) {
                    Output::instance()->resultCode(code_keyword_repeat, $keywordExist. " 关键字重复");
                    return;
                }
            }

            /** 4. 一起添加到关键字表 */
            $guid = Encryption::uuid();
            $date = date('Y-m-d H:i:s');

            $keys = explode(',', $keys);
            $data = [];
            foreach ($keys as $k => $v) {
                $d = [
                    'id'            => $guid,
                    'mediaId'       => $mediaId,
                    'ruleName'      => $ruleName,
                    'materialId'    => 0,   // 添加keys时, 素材还没有添加, 先默认为0
                    'keyword'       => $v,
                    'exactMatch'    => $exactMatch,
                    'updateTime'    => $date,
                    'deleted'       => 0
                ];

                array_push($data, $d);
            }

            $result_id = $MaterialKeyword_Model->addAll($data);

            $MaterialKeyword_sql = $MaterialKeyword_Model->getLastSql();
            R('Log/add', array('indmediaManagement', '139', '自媒体管理', op_add, $MaterialKeyword_sql, $this->getLoginName() . '在自媒体消息回复中创建了一套关键字组'));

            /** 5. 返回 */
            if ($needReturn) {
                return $result_id;
            }

            if ($result_id) {
                Output::instance()->object([
                    'code'  => 0,
                    'msg'   => '关键字创建成功',
                    'data'  => [
                        'id'    => $guid
                    ]
                ]);
            } else {
                Output::instance()->resultCode(code_sql_error);
            }

        } else {    /** 否则这里是对现有的keys做差集修改 */

            /**
             * 对keys做修改
             * 1. 需要删掉的把这个自媒体下的这个id下的这个key对应的多条都删除
             * 2. 需要添加的需要在这个自媒体下这个对应id下把这个可以对应的素材都添加一遍
             * 3. 不需要动的
             */
            $keys_info = $MaterialKeyword_Model
                ->where(['id' => $id, 'mediaId' => $mediaId])
                ->group('keyword')
                ->select();
            $keys_old = array_column($keys_info, 'keyword');
            $keys_new = explode(',', $keys);

            $keys_add = array_values(array_diff($keys_new, $keys_old));
            $keys_del = array_values(array_diff($keys_old, $keys_new));

            /** 删除keys */
            $where_del = [
                'id'        => $id,
                'mediaId'   => $mediaId,
                'keyword'   => array('in', $keys_del)
            ];
            $result_del = $MaterialKeyword_Model->where($where_del)->save(['deleted' => 1]);

            /** 增加keys */
            $date = date('Y-m-d H:i:s');
            $data_add = [];
            foreach ($keys_add as $k_add => $v_add) {   // 遍历新增的key值
                foreach ($keys_info as $k_info => $v_info) {    // 遍历这个key对应的多个素材
                    $d_add = [
                        'id'            => $id,
                        'mediaId'       => $mediaId,
                        'ruleName'      => $v_info['ruleName'],
                        'materialId'    => $v_info['materialId'],
                        'keyword'       => $v_add,  // 新增的key值对应, 其他都一样
                        'exactMatch'    => $v_info['exactMatch'],
                        'updateTime'    => $date,
                        'deleted'       => 0
                    ];

                    array_push($data_add, $d_add);
                }
            }
            $result_add = $MaterialKeyword_Model->addAll($data_add);

            $MaterialKeyword_sql = $MaterialKeyword_Model->getLastSql();
            R('Log/add', array('indmediaManagement', '139', '自媒体管理', op_add, $MaterialKeyword_sql, $this->getLoginName() . '在自媒体消息回复中重新设置了id为: ' . $id . '的关键字组'));

            if ((isset($result_del) && !$result_del)
                || (isset($result_add) && !$result_add)) {
                Output::instance()->resultCode(code_sql_error);
            } else {
                Output::instance()->resultCode();
            }

        }

    }

    /**
     * 获得目前设置的关键字
     *
     * @param $keyId    关键字keyId
     * @param $mediaId  自媒体id
     */
    public function getKeys($keyId, $mediaId)
    {
        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $MaterialKeyword_Model  = M('material_keyword');

        /** 3. 查询数据 */
        $where_MK = ['id' => $keyId, 'mediaId' => $mediaId];
        $keys = $MaterialKeyword_Model->where($where_MK)->group('keyword')->getField('keyword', TRUE);

        /** 4. 返回 */
        Output::instance()->object([
            'code'  => 0,
            'msg'   => '关键字查询成功',
            'data'  => [
                'keys'  => $keys
            ]
        ]);
    }

    /**
     * 设置某个消息互动的规则的访问标签
     *
     * @param $keyId    规则key的id
     * @param $mediaId  自媒体id
     * @param $tags     访问标签, 由 "," 分割的字符串
     */
    public function setTags($keyId, $mediaId, $tags)
    {
        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $Material_Model         = M('material');
        $MaterialKeyword_Model  = M('material_keyword');

        /**
         * 3. 根据keyId查询出这个规则所有的素材
         * 由于老版本是一对一的, 所以访问标签直接写在素材之中, 现在多对多, 这个访问标签只能冗余了, 这样也可以很好的兼容以前
         */
        $materialIds = $MaterialKeyword_Model->where(['id' => $keyId, 'mediaId' => $mediaId])->group('materialId')->getField('materialId', true);
        // 如果素材id为空, 表名只有关键字而没有对应素材, 要求至少先创建一个素材
        if (in_array(0, $materialIds)) {
            Output::instance()->object([
                'code'  => 1,
                'msg'   => '请至少先创建一个素材'
            ]);
            exit;
        }

        $where['id']      = array('in', $materialIds);
        $where['deleted'] = array('eq', 0);
        $data = ['accessTag' => $tags];

        $result = $Material_Model->where($where)->save($data);

        $Material_sql = $Material_Model->getLastSql();
        R('Log/add', array('indmediaManagement', '139', '自媒体管理', op_add, $Material_sql, $this->getLoginName() . '在自媒体消息回复中设置了规则id为: ' . $keyId . '的访问标签'));

        /** 4. 返回 */
        if (is_numeric($result)) {
            Output::instance()->resultCode();
        } else {
            Output::instance()->resultCode(code_sql_error);
        }


    }

    /**
     * 获取某个消息互动的规则的访问标签
     *
     * @param $keyId    规则key的id
     * @param $mediaId  自媒体id
     */
    public function getTags($keyId, $mediaId)
    {
        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $Material_Model         = M('material');
        $MaterialKeyword_Model  = M('material_keyword');

        /** 3 组织数据 */
        // 由于一个规则的所有素材的访问标签都是冗余的, 所以只需要查出一个就可以了
        $materialId = $MaterialKeyword_Model->where(['id' => $keyId, 'mediaId' => $mediaId])->getField('materialId');
        $accessTag = $Material_Model->where(['id' => $materialId])->getField('accessTag');
        $arr_accessTag = explode(',', $accessTag);

        // 平台所有的访问标签
        $allTags = R('AccessTag/getAccessTag', [null, $mediaId, true]);

        // 遍历系统所有的标签, 组织选中情况
        foreach ($allTags as $k => $tag) {
            $allTags[$k]['isSelect'] = (in_array($tag['id'], $arr_accessTag)) ? 1 : 0;
        }

        /** 4. 返回 */
        Output::instance()->object([
            'code'  => 0,
            'msg'   => 'API调用成功',
            'data'  => $allTags
        ]);
    }

    /**
     * 添加关键字对应素材
     *
     * @param        $id            关键字id
     * @param        $mediaId       自媒体id
     * @param        $name          素材名称
     * @param        $module        text-文字/news-图文
     * @param        $xml           内容
     * @param string $tags
     * @param null   $accessTag     访问标签
     */
    public function addKeyMaterial($id, $mediaId, $name, $module, $xml, $tags = '', $accessTag = NULL)
    {
        /**
         * 添加素材, 要求必须先添加关键字
         */

        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 关键字判断 */
        if (!isset($id)) {
            Output::instance()->object([
                'code'  => 1,
                'msg'   => '请先添加关键字',
                'data'  => []
            ]);
        }

        /** 3. 调用素材添加方法, 添加素材 */
        $mid = R('Material/addData', array($name, $module, $xml, $public = '', $type = '', $groupId = '', $tags, 0, NULL, $accessTag));

        /** 4. 修改关键字与素材的对应关系 */
        $result = $this->addMaterialKeys($id, $mid, $mediaId);

        /** 5. 返回 */
        if ($result != false) {
            Output::instance()->object([
                'code'  => 0,
                'msg'   => '素材添加成功',
                'data'  => [
                    'result'    => $result
                ]
            ]);
        } else {
            Output::instance()->object([
                'code'  => 1,
                'msg'   => '素材添加失败',
                'data'  => []
            ]);
        }

    }

    /**
     * 获取关键字对应素材概览信息
     *
     * @param        $mediaId   自媒体id
     * @param null   $keys      关键字, 多个使用 "," 分割
     * @param string $order     排序字段
     * @param string $orderBy   排序规则
     * @param int    $start     分页
     * @param int    $limit
     */
    public function getKeyMaterialInfo($mediaId, $keys = NULL, $order = 'updateTime', $orderBy = 'desc', $start = 0, $limit = 10000)
    {
        /**
         * 获得概览信息, 主要是keys => 素材类型及个数
         * 1. 被添加自动回复 & 消息默认回复 可以看做是对keys进行筛选的
         *      如果传了这两个关键字, 可是又没有查到信息, 则新建, 这只会在第一次时发生
         * 2. keys可以不传, 不传则筛选关键字回复, 传了keys要是是 "," 分割的字符串
         *
         * 通过keys查询包含这些keys的key的整体id -> 为了将key分组查出整体
         * 再遍历这个整体id, 对每个整体的下的materialId进行去重
         * 最后通过这个素材id去查素材类型, 拼装最后的数据
         */

        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $Material_Model         = M('material');
        $MaterialKeyword_Model  = M('material_keyword');

        /** 3. 查询数据 */
        // 查询key_id集合,
        $where_key_id['mediaId'] = $mediaId;
        $where_key_id['deleted'] = 0;
        if (isset($keys)) {
            $arr_keys = explode(',', $keys);    // 传过来的keys
            if (count($arr_keys) == 1) {    // 为了性能优化 -> 因为大多传keys进来只是一个, 被添加自动回复 | 消息默认回复
                $where_key_id['keyword'] = $arr_keys[0];

                /** 这是特殊情况, 查询 被添加自动回复 | 消息默认回复 , 如果没查到, 先内部实现增加一个, 只增加一个, 也就是只会走一次这里 */
                if ($arr_keys[0] == 'system_subscribe' || $arr_keys[0] == 'default_reply') {    // 一个词关键词的情况有多中, 这两种特殊情况才做处理
                    $keyId_old = $MaterialKeyword_Model->where($where_key_id)->getField('id');
                    if (!isset($keyId_old)) {   // 如果没有设置, 则内部创建
                        $keyId_new = $this->setKeys(null, $mediaId, $arr_keys[0], 1, '', true);

                        if (!isset($keyId_new)) {
                            Output::instance()->resultCode(code_sql_error);
                            exit;
                        }
                    }
                }
            } else {    // 否则可能是多个keys, 用in查询
                $where_key_id['keyword'] = array('in', $arr_keys);
            }
        } else {    // 如果没传关键字, 是默认查询的话, 刨除 system_subscribe && default_reply 两个值
            $where_key_id['keyword'] = array('not in', ['system_subscribe', 'default_reply']);
        }
        $key_ids = $MaterialKeyword_Model
            ->where($where_key_id)
            ->field('id')
            ->group('id')
            ->order($order, $orderBy)
            ->limit($start, $limit)
            ->select();

        $result_data = [];
        foreach ($key_ids as $k_id => $v_id) {
            // 查询这个key_id对应的所有key
            $where_key['id']      = $v_id['id'];    // 这个id不能唯一指定, 所以下面用的是select也是必要的, 也是对的
            $where_key['deleted'] = 0;

            $result_info = $MaterialKeyword_Model->where($where_key)->group('materialId')->field('materialId, keyword')->select();
            // 由于按照materialId进行分组, 所以keyword可能重复, 这里进行一些去重
            $result_keys = array_column($result_info, 'keyword');
            $result_keys = array_keys(array_flip($result_keys));
            $result_materialIds = array_column($result_info, 'materialId');
            // 遍历materialIds查询各类型素材及个数
            $text = $news = $image = $voice = $video = 0;
            foreach ($result_materialIds as $k_mid => $v_mid) {
                $where_material['id'] = $v_mid;
                $result_material_info = $Material_Model->where($where_material)->find();
                switch ($result_material_info['module']) {
                    case 'text':  $text++;  break;
                    case 'news':  $news++;  break;
                    case 'image': $image++; break;
                    case 'voice': $voice++; break;
                    case 'video': $video++; break;
                    default : break;
                }
            }

            $r = [
                'key_id'    => $v_id['id'],
                'keys'      => $result_keys,
                'materials' => [
                    ['num' => $text, 'name' => '文本'],
                    ['num' => $news, 'name' => '图文'],
                    ['num' => $image, 'name' => '图片'],
                    ['num' => $voice, 'name' => '语音'],
                    ['num' => $video, 'name' => '视频']
                ]
            ];
            array_push($result_data, $r);
        }

        Output::instance()->object([
            'code'  => 0,
            'msg'   => 'API调用成功',
            'data'  => $result_data
        ]);

    }

    /**
     * 获取关键字对应素材详情
     *
     * @param      $keyId       关键字id
     * @param      $mediaId     自媒体id
     * @param bool $toBr
     */
    public function getKeyMaterialDetail($keyId, $mediaId, $toBr = true)
    {
        /**
         * 更加keyId查询materialId, 再去material里查询素材信息
         */

        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $Material_Model         = M('material');
        $MaterialKeyword_Model  = M('material_keyword');

        /** 3. 查询数据 */
        $where_MK = ['id' => $keyId, 'mediaId' => $mediaId, 'deleted' => 0];
        $materialIds = $MaterialKeyword_Model->where($where_MK)->group('materialId')->getField('materialId', TRUE);

        // 处理组织素材数据
        $materials = [];
        if (!in_array(0, $materialIds)) {   // 这个素材id数组里不包含数值0, 因为如果0在里面, 表示它还没有任何素材
            foreach ($materialIds as $k_mId => $v_mId) {
                $where_material['id'] = $v_mId;

                $result_material = $Material_Model->where($where_material)->find();
                if ($toBr && $result_material['xml'] != '') {
                    $result_material['xml'] = nl2br($result_material['xml']);
                }

                array_push($materials, $result_material);
            }
        }

        /** 4. 返回 */
        if (!empty($materials)) {
            // 按照id倒叙排列
            $arr_sort = array_sort($materials, 'id', 'desc');
            if (is_array($arr_sort)) {
                $materials = $arr_sort;
            }

            Output::instance()->object([
                'code'  => 0,
                'msg'   => 'API调用成功',
                'data'  => $materials
            ]);
        } else {
            Output::instance()->resultCode();
        }
    }

    /**
     * 获取素材详情 - 这里虽然已经完全是素材信息了, 可是为了统一, 把接口放在这里, 代码可能在MaterialAction里
     *
     * @param $materialId   素材id
     */
    public function getMaterialDetail($materialId)
    {
        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $Material_Model         = M('material');

        /** 3. 查询数据 */
        $result = $Material_Model->where(['id' => $materialId])->find();

        if ($result) {
            Output::instance()->object([
                'code'  => 0,
                'msg'   => '素材查询成功',
                'data'  => $result
            ]);
        } else {
            Output::instance()->resultCode(code_sql_error);
        }
    }

    /**
     * 修改关键字对应的素材信息
     *
     * @param        $materialId    素材id
     * @param        $mediaId
     * @param        $name
     * @param        $module
     * @param        $xml
     * @param string $tags
     * @param null   $accessTag
     */
    public function updateKeyMaterial($materialId, $mediaId, $name, $module, $xml, $tags = '', $accessTag = NULL)
    {
        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 调用素材添加方法, 添加素材 */
        // 需要操作微信资源, 加上参数$mediaId
        $update_result = R('Material/updateData', array($materialId, $name, $module, $xml, $tags, 0, $accessTag, 0, $mediaId));

        /** 3. 返回 */
        if ($update_result) {
            Output::instance()->resultCode();
        } else {
            Output::instance()->resultCode(code_sql_error);
        }
    }

    /**
     * 删除关键字对应素材
     *
     * @param      $materialId  素材id
     * @param      $mediaId     自媒体id
     * @param bool $needReturn  是否是内部接口调用返回, true-是, 则不需要想也没打印东西
     * @return bool|void
     */
    public function delKeyMaterial($materialId, $mediaId, $needReturn = FALSE)
    {
        /**
         * 删除一个素材, 需要注意删除素材对应的关键字关联
         */

        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$needReturn && !$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $Material_Model         = M('material');
        $MaterialTags_Model     = M('material_tags');
        $MaterialKeyword_Model  = M('material_keyword');

        /** 3. 处理数据 */
        // 先删除素材和关键字的
        $where_key['materialId'] = $materialId;
        $result_key = $MaterialKeyword_Model->where($where_key)->save(['updateTime' => date('Y-m-d H:i:s'), 'deleted' => 1]);

        // 删除素材和tags
        $where_tags['materialId'] = $materialId;
        $result_tags = $MaterialTags_Model->where($where_tags)->delete();

        // 删除素材信息
        // TODO: 有media_id时, 需要删除微信资源
        $where_material['id'] = $materialId;
        $material = $Material_Model->where($where_material)->find();
        if (isset($material['media_id'])) {     // 如果media_id有值, 则表明有资源上传到了微信, 需要把它删除
            WeixinApi::del_material($material['media_id'], $mediaId);
        }

        $result_material = $Material_Model->where($where_material)->save(['media_id' => null, 'updateTime' => date('Y-m-d H:i:s'), 'deleted' => 1]);

        $Material_sql = $Material_Model->getLastSql();
        R('Log/add', array('indmediaManagement', '139', '自媒体管理', op_add, $Material_sql, $this->getLoginName() . '在自媒体消息回复中删除了素材id为: ' . $materialId . '的素材内容'));

        /** 4. 返回 */
        if ($needReturn) {
            if (is_numeric($result_key) && is_numeric($result_tags) && is_numeric($result_material)) {
                return true;
            }
            return false;
        }

        if (is_numeric($result_key) && is_numeric($result_tags) && is_numeric($result_material)) {
            Output::instance()->resultCode();
        } else {
            Output::instance()->resultCode(code_sql_error);
        }

    }

    /**
     * 删除一个消息互动规则
     *
     * @param $keyId    关键字id
     * @param $mediaId  自媒体id
     */
    public function delRule($keyId, $mediaId)
    {
        /** 1. 登录判断 */
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        /** 2. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $MaterialKeyword_Model  = M('material_keyword');

        /** 3. 查询关键字keyId下关联的所有素材 */
        $where_MK = ['id' => $keyId, 'mediaId' => $mediaId, 'deleted' => 0];
        $materialIds = $MaterialKeyword_Model->where($where_MK)->group('materialId')->getField('materialId', TRUE);

        // 调用上面那个接口
        $flag = true;
        foreach ($materialIds as $k_mId => $v_mId) {
            $result = $this->delKeyMaterial($v_mId, $mediaId, TRUE);
            if (!$result) {     // result值为false, 说明上面删除素材相关内容有错误
                $flag = false;
            }
        }

        /** 4. 返回 */
        if ($flag) {
            Output::instance()->resultCode();
        } else {
            Output::instance()->resultCode(code_sql_error);
        }

    }

    /*
    |--------------------------------------------------------------------------
    |                           以下为该类私有方法
    |--------------------------------------------------------------------------
    */

    /**
     * 添加关键字对素材资源的关联
     *
     * @param     $id           关键字id
     * @param     $mid          素材id
     * @param int $mediaId      自媒体账号
     * @return bool|string|void
     */
    private function addMaterialKeys($id, $mid, $mediaId = 0)
    {
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }
        /** 1. 实例化数据模型 */
        $customerId = Session::$user['customerId'];
        Session::switchCustomer(0);
        Session::switchCustomer($customerId);
        $MaterialKeyword_Model  = D('material_keyword');

        /** 2. 判断现有关键字对素材的状态 */
        $where_MK = [
            'id'        => $id,
            'mediaId'   => $mediaId,
            'deleted'   => 0
        ];
        $data_MK = $MaterialKeyword_Model->where($where_MK)->group('keyword')->select();

        /** 3. 循环这些key的id下的所有key */
        if ($data_MK[0]['materialId'] == 0) { // 说明这个素材是第一次添加, 现有的这些key所对应的materialId都还是0, 需要修改它
            $data_update['materialId'] = $mid;

            $result = $MaterialKeyword_Model->where($where_MK)->save($data_update);

            $MaterialKeyword_sql = $MaterialKeyword_Model->getLastSql();
            R('Log/add', array('indmediaManagement', '139', '自媒体管理', op_add, $MaterialKeyword_sql, $this->getLoginName() . '在自媒体消息回复中修改了id为: ' . $id . '的素材内容'));

        } else {    // 这个素材是第多次添加素材, 那么得一次添加关联
            $data_add = [];
            foreach ($data_MK as $k => $v_MK) {
                $date = date('Y-m-d H:i:s');
                $add = [
                    'id'        => $id,
                    'mediaId'   => $v_MK['mediaId'],
                    'ruleName'  => $v_MK['ruleName'],
                    'materialId'=> $mid,
                    'keyword'   => $v_MK['keyword'],
                    'exactMatch'=> $v_MK['exactMatch'],
                    'updateTime'=> $date,
                    'deleted'   => 0
                ];

                array_push($data_add, $add);
            }

            $result = $MaterialKeyword_Model->addAll($data_add);

            $MaterialKeyword_sql = $MaterialKeyword_Model->getLastSql();
            R('Log/add', array('indmediaManagement', '139', '自媒体管理', op_add, $MaterialKeyword_sql, $this->getLoginName() . '在自媒体消息回复中修改了id为: ' . $id . '的素材内容'));

        }

        return $result;
    }


    /**
     * 获取登录者姓名
     */
    private function getLoginName()
    {
        $cuid = Session::$user['cuid'];
        $customerId = Session::$user['custoerId'];

        Session::switchCustomer(0);
        $Model_CustomerUser = M('customer_user');
        Session::switchCustomer($customerId);

        $loginName = $Model_CustomerUser->where(['id' => $cuid, 'deleted' => 0])->getField('loginName');

        return $loginName;
    }

}